package classifieurs;

import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

import mainprogram.Statistiques;

import extraction.Categorie;
import extraction.Tweet;

import tools.FrenchTokenizer;
import tools.Normalizer;

public class ClassificationBinomiale extends Classification{

	public ClassificationBinomiale(HashMap<String, Categorie> statParClasse) {
		super(statParClasse);
	}

	/**
	 * Maps pour ranger les parametres betas - 1 par catégorie: <mot, parametre> 
	 */
	public HashMap<String, Float> mapPos = new HashMap<String, Float>();
	public HashMap<String, Float> mapNeg = new HashMap<String, Float>();
	public HashMap<String, Float> mapNeu = new HashMap<String, Float>();
	public HashMap<String, Float> mapIrr = new HashMap<String, Float>();


	/**
	 * comptes pour binomial
	 */
	public void modeleBinomial(){
		//<mot <nbDansPositive, nbDansNegative, nbDansNeutral, nbDansIrrelevant>>
		HashMap<String, ArrayList<Float>> mapBinomial = new HashMap<String, ArrayList<Float>>();

		ArrayList<Float> tabMapBinomial;
		HashMap<String, Integer> hashPos = positive.getMotsTweet();
		HashMap<String, Integer> hashNeg = negative.getMotsTweet();
		HashMap<String, Integer> hashNeu = neutral.getMotsTweet();
		HashMap<String, Integer> hashIrr = irrelevant.getMotsTweet();

		/*Tous les mots dans mapBinomial avec le tableau correspondant*/
		for(String mot : DataClassification.mots){
			tabMapBinomial = new ArrayList<Float>(4);
			if (hashPos.get(mot) == null)
				tabMapBinomial.add(epsilon);
			else
				tabMapBinomial.add((float)hashPos.get(mot));
			if (hashNeg.get(mot) == null)
				tabMapBinomial.add(epsilon);
			else
				tabMapBinomial.add((float)hashNeg.get(mot));
			if (hashNeu.get(mot) == null)
				tabMapBinomial.add(epsilon);
			else
				tabMapBinomial.add((float)hashNeu.get(mot));
			if (hashIrr.get(mot) == null)
				tabMapBinomial.add(epsilon);
			else
				tabMapBinomial.add((float)hashIrr.get(mot));

			mapBinomial.put(mot, tabMapBinomial);
		}
		/**/

		Float betaPos;
		Float betaNeg;
		Float betaNeu;
		Float betaIrr;
		for (Entry<String, ArrayList<Float>> entry : mapBinomial.entrySet()){
			//nbr docs contenant ce mot (dans la classe) sur nb tot docs dans classe
			betaPos = (float) entry.getValue().get(0)/ positive.getListeTweet().size();
			betaNeg = (float) entry.getValue().get(1)/ negative.getListeTweet().size();
			betaNeu = (float) entry.getValue().get(2)/ neutral.getListeTweet().size();
			betaIrr = (float) entry.getValue().get(3)/ irrelevant.getListeTweet().size();
			mapPos.put(entry.getKey(), betaPos );
			mapNeg.put(entry.getKey(), betaNeg );
			mapNeu.put(entry.getKey(), betaNeu );
			mapIrr.put(entry.getKey(), betaIrr );
		}
	}


	/**
	 * découpe fichier en 10 parties
	 * 1 = test, 9=apprentissage
	 * Répétition 10 fois en changeant bloc test
	 */
	public HashMap<String, Integer> validationCroisee(){
		ArrayList<Tweet> listeTweet = test_positive.getListeTweet();
		listeTweet.addAll(test_negative.getListeTweet());
		listeTweet.addAll(test_neutral.getListeTweet());
		listeTweet.addAll(test_irrelevant.getListeTweet());

		int ok=0;
		int nonok=0;
		HashMap<String, Integer> err_positive = new HashMap<String, Integer>();
		HashMap<String, Integer> err_negative = new HashMap<String, Integer>();
		HashMap<String, Integer> err_neutral = new HashMap<String, Integer>();
		HashMap<String, Integer> err_irrelevant = new HashMap<String, Integer>();

		for (Tweet t : listeTweet){
			//System.out.println("tweet choisi : "+t.getSentiment()+" --> " +t.getTweetText());
			float vraisPos = calculVraisemblanceBinomial(t, mapPos);
			float vraisNeg = calculVraisemblanceBinomial(t, mapNeg);
			float vraisNeu = calculVraisemblanceBinomial(t, mapNeu);
			float vraisIrr = calculVraisemblanceBinomial(t, mapIrr);
			float max;

			max = (vraisNeg > vraisPos) ? vraisNeg : vraisPos;
			max = (vraisNeu > max) ? vraisNeu : max;
			max = (vraisIrr > max) ? vraisIrr : max;

			String max_string = null;
			if (max==vraisPos) max_string = "positive";
			else if (max==vraisNeg) max_string = "negative";
			else if (max==vraisNeu) max_string = "neutral";
			else if (max==vraisIrr) max_string = "irrelevant";


			if(t.getSentiment().equals("test_"+max_string)){
				ok++;
			}
			else{
				nonok++;
			}
			if (max_string.contains("positive")){
				if (err_positive.get(t.getSentiment()) == null)
					err_positive.put(t.getSentiment(), 1);
				else 
					err_positive.put(t.getSentiment(), err_positive.get(t.getSentiment())+1);
			}
			else if (max_string.contains("negative")){
				if (err_negative.get(t.getSentiment()) == null)
					err_negative.put(t.getSentiment(), 1);
				else
					err_negative.put(t.getSentiment(), err_negative.get(t.getSentiment())+1);
			}
			else if (max_string.contains("neutral")){
				if (err_neutral.get(t.getSentiment()) == null)
					err_neutral.put(t.getSentiment(), 1);
				else
					err_neutral.put(t.getSentiment(), err_neutral.get(t.getSentiment())+1);
			}
			else if (max_string.contains("irrelevant")){
				if (err_irrelevant.get(t.getSentiment()) == null)
					err_irrelevant.put(t.getSentiment(), 1);
				else
					err_irrelevant.put(t.getSentiment(), err_irrelevant.get(t.getSentiment())+1);
			}

		}
		System.out.println("ok="+ok+" et nonok="+nonok+" --> pourcentage nonok : "+ ((float)nonok/(ok+nonok)));
		System.out.println("erreurs matrice : ");
		System.out.println("positive : "+err_positive);
		System.out.println("negative : "+err_negative);
		System.out.println("neutral : "+err_neutral);
		System.out.println("irrelevant : "+err_irrelevant);

		//return ((float)nonok/(ok+nonok));
		return err_irrelevant;

	}
	
	/**
	 * découpe fichier en 10 parties
	 * 1 = test, 9=apprentissage
	 * Répétition 10 fois en changeant bloc test
	 */
	public void validation(){
		ArrayList<Tweet> listeTweet = test_polarite.getListeTweet();
		FileWriter fw;
		try {
			fw = new FileWriter("test-eit-12.txt");
			for (Tweet t : listeTweet){
				//System.out.println("tweet choisi : "+t.getSentiment()+" --> " +t.getTweetText());
				float vraisPos = calculVraisemblanceBinomial(t, mapPos);
				float vraisNeg = calculVraisemblanceBinomial(t, mapNeg);
				float vraisNeu = calculVraisemblanceBinomial(t, mapNeu);
				float vraisIrr = calculVraisemblanceBinomial(t, mapIrr);
				float max;

				max = (vraisNeg > vraisPos) ? vraisNeg : vraisPos;
				max = (vraisNeu > max) ? vraisNeu : max;
				max = (vraisIrr > max) ? vraisIrr : max;

				String max_string = null;
				if (max==vraisPos) max_string = "positive";
				else if (max==vraisNeg) max_string = "negative";
				else if (max==vraisNeu) max_string = "neutral";
				else if (max==vraisIrr) max_string = "irrelevant";

				//System.out.println("tweet : "+t.getTweetText()+" + polarite : "+max_string);

				fw.write("\""+max_string+"\"\n");
				
			} 
			fw.close();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}




	/**
	 * Calcul vraisemblance pour 1 doc
	 * @param tweet : document considéré
	 * @param mapCategorie : liste des mots du dico pour cette classe avec leurs parametres respectifs
	 * @return inference : <0, plus elle est proche de 0, plus le Tweet est proche de la catégorie concernée
	 */
	public float calculVraisemblanceBinomial (Tweet tweet, HashMap<String, Float> mapCategorie){
		float vraisemblance = 0;
		ArrayList<String> tabMotsDoc = 	tweet.getMotsTweetText();
		//parcour map dico
		for (Entry<String, Float> entry : mapCategorie.entrySet()){
			//mot présent dans doc ?
			if (tabMotsDoc.contains(entry.getKey())){
				//vraisemblance 
				vraisemblance += Math.log(entry.getValue());
			}
			else
				vraisemblance += Math.log(1-entry.getValue());
		}
		return vraisemblance;
	}

	public static void main(String[] args) {
		Statistiques stats = new Statistiques();
		DataClassification d = new DataClassification();
		try {
			stats.analyseFichier("./train.txt"); //remplit statParClasse (analyse avec extraction)
			d.mots_significatifs = stats.getMotsMoinsSignificatifs(); //remplit la map mots_significatifs
			//d.mots_significatifs = stats.getMotsPlusSignificatifs();
			//remplissage des map
			d.analyseFichier("./trainMelange.txt");
			Classification cl;
			HashMap<String, Integer> err;
			float err_pos_neg = 0;
			float err_pos_pos = 0;
			float err_pos_neu = 0;
			float err_pos_irr = 0;

			for (int i=0; i<10; i++){
				cl = new ClassificationBinomiale(d.mapStatParClass.get(i));
				((ClassificationBinomiale) cl).modeleBinomial();
				err =  ((ClassificationBinomiale) cl).validationCroisee();
				if (err.get("test_negative") != null)
					err_pos_neg += err.get("test_negative");
				if (err.get("test_positive") != null)
					err_pos_pos += err.get("test_positive");
				if (err.get("test_neutral") != null)
					err_pos_neu += err.get("test_neutral");
				if (err.get("test_irrelevant") != null)
					err_pos_irr += err.get("test_irrelevant");
			}

			System.out.println("erreur moyenne neg neg: "+ (float)err_pos_neg/10);
			System.out.println("erreur moyenne neg pos : "+ (float)err_pos_pos/10);
			System.out.println("erreur moyenne neg neu : "+ (float)err_pos_neu/10);
			System.out.println("erreur moyenne neg irr : "+ (float)err_pos_irr/10);

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
